from pathlib import Path
import random
import time
import re

import pyautogui
import pandas as pd
import openpyxl
import xlrd

from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import MoveTargetOutOfBoundsException
from bs4 import BeautifulSoup

from . import browser
import proxy_with_authorization
from . import append_to_excel
from . import search_mail


class Tools(browser.Browser):

    """ Инструменты для работы с браузером """

    def wait(self, f=2, b=3.5):

        """ Чуть-чуть подождать """

        number = random.uniform(f, b)
        print(f'Ждем {number}\n')
        time.sleep(number)


    def click_on_button(self, element_selenium, a=.5, b=.8):

        """ Нажать на кнопку """

        element_selenium.click()    # Кликаем на элемент
        self.wait(a, b)             # Чуть-чуть ждем


    def enter_text_in_field(self, element_selenium, text, a=.5, b=.8):

        """ Ввести текст в поле """

        element_selenium.click()
        element_selenium.clear()
        element_selenium.send_keys(text)
        self.wait(a, b)


    def move_to_element(self, browser, selenium_element, a=.5, b=.8):

        """ Переместится к элементу страницы """

        action = ActionChains(browser)
        action.move_to_element(selenium_element)
        action.perform()
        self.wait(a, b)


    def scroll_the_page_js(self, browser, a=.2, b=.5, w=0, h=50):

        """
        Переместиться по странице js
        a - задержка от
        b - задержка до
        w - прокрутить страницу по ширине
        h - прокрутить страницу по высоте
        """

        browser.execute_script(f"window.scrollBy({w}, {h})")
        self.wait(a, b)


    def get_configured_browser(self, proxy=False, private_proxies=False):

        """ Получить настроенный браузер """

        if proxy:  # Если необходимо делать запрос через общедоступные прокси

            browser = self.get_browser(self.display_browser, proxy, private_proxies)
            return browser

        elif private_proxies:  # Если необходимо делать запрос через приватные прокси

            def get_information_for_proxy(proxy):

                pass


            # ВЫШЕ ОПРЕДЕЛЕНИЕ ФУНКЦИЙ

            host, port, username, password = get_information_for_proxy(proxy)
            browser = proxy_with_authorization.proxy_chrome(host, port, username, password)

            return browser

        else:  # Если прокси не используюется

            browser = self.get_browser(self.display_browser)
            return browser


    def add_data_to_excel(self, data):

        """ Добавляем данные в excel """

        address, type_of_activity, company_name, all_numbers, email_yandex_map, email_site, site_links, full_address = data

        df = pd.DataFrame({
            'Локация (город, район)': [address],
            'Вид деятельности': [type_of_activity],
            'Название компании': [company_name],
            'Телефоны': [all_numbers],
            'Емейл (указанный на Яндекс картах)': [email_yandex_map],
            'Сайт': [email_site],
            'Собранные почты': [site_links],
            'Адрес (указанный на яндекс картах)': [full_address]

        })
        #append_to_excel.append_df_to_excel('./data.xlsx', df, header=None, index=False)
        append_to_excel.append_df_to_excel('./data.xlsx', df, index=False)


    def bring_excel_to_the_desired_from(self):

        """ Приводим файл excel в нужный вид """
        """ Тут вообще непонятно что творится, я сам еле сделал это """

        filename = ('data.xlsx')
        df = pd.read_excel('data.xlsx')

        wb = openpyxl.load_workbook(filename)
        worksheet = wb.active
        print(len(df))
        sheet = wb['Sheet1']

        print(sheet['A1'].value)

        for count, name in enumerate(range(len(df)), 1):

            point = f'A{count}'
            text = sheet[point].value

            if text == 'Локация (город, район)' and count > 1:

                print('Удалили')
                sheet.delete_rows(count, 1)
                wb.save(filename)


    def waiting_for_one_thing(self, browser, first_element_xpath, second_element_xpath, disable=False):

        """ Ожидаем появления одного из двух элементов """

        def get_the_first_element(browser, xpath):

            """ Получаем первый элемент """

            try:

                element_selenium = browser.find_element(
                    By.XPATH,
                    xpath
                )
                print('Первый элемент был найден')

                return 'first element'

            except NoSuchElementException as error:

                print('Первый элемент не был найден')
                return 'not found'


        def get_the_second_element(browser, xpath):

            """ Получаем второй элемент """

            try:

                element_selenium = browser.find_element(
                    By.XPATH,
                    xpath
                )
                print('Второй элемент был найден')

                return 'second element'

            except NoSuchElementException as error:

                print('Второй элемент не был найден')
                return 'not found'


        # ВЫШЕ ОПРЕДЕЛЕНИЕ ФУНКЦИЙ

        count = 0

        while True:

            if count == 7 and disable == True: return 'elements are missing'

            first_element = get_the_first_element(browser, first_element_xpath)
            if not 'not found' in first_element: return first_element

            second_element = get_the_second_element(browser, second_element_xpath)
            if not 'not found' in second_element: return second_element

            time.sleep(1)
            count += 1


    def open_the_desired_page(self, link, proxy=False, private_proxies=False):

        """ Получаем браузер с нужной страницей """

        browser = self.get_configured_browser(proxy, private_proxies)
        browser.get(link)
        browser.maximize_window()

        return browser


    def get_addresses(self, what_here):

        """ Работаем с адресами """

        list_of_addresses = []
        folder = Path('../yandex_map_two')

        with open(folder/'addresses.txt', encoding='utf-8') as file:

            for line in file:

                list_of_addresses.append(line.strip())

        match what_here:

            case 'all':

                return list_of_addresses

            case ['last']:

                last_addresses = list_of_addresses[-1]
                return last_addresses

            case _:

                print(f'Непонятно какой адрес нужен\nwhat_here - {what_here}')


    def scroll_the_sidebar(self, height=-2000):

        """ Пролистываем сайдбар """

        logo_image = pyautogui.locateOnScreen('images/logo.png', confidence=0.5)
        point = pyautogui.center(logo_image)
        pyautogui.moveTo(point.x, point.y, 1)
        pyautogui.moveTo(100, 300, 1)
        pyautogui.scroll(-2000)


    def scroll_further(self, browser):

        """ Листаем дальше? """

        try:

            show_more_button = browser.find_element(
                By.XPATH,
                '//div[@class="add-business-view"]'
            )
            self.scroll_the_sidebar()
            print('Кнопки "Показать больше" нет')

            return 'end'

        except NoSuchElementException as error:

            return 'scroll on'


    def get_a_list_of_links_to_places(self, browser):

        """ Получаем список ссылок на места """

        link_list_of_places = []

        links_of_list = browser.find_elements(
            By.XPATH,
            '//a[@class="search-snippet-view__link-overlay"]'
        )

        for element in links_of_list:

            link = element.get_attribute('href')
            link_list_of_places.append(link)

        browser.quit()

        return link_list_of_places


    def move_to_the_last_element(self, browser, what_here):

        """ Перемещаемся к последнему элементу """

        def work_with_the_first_group(browser):

            """ Работаем с первой группой """

            while True:

                self.scroll_the_sidebar()

                well_what = self.scroll_further(browser)
                if well_what == 'end': break


        def work_with_the_second_group(browser):

            """ Работаем со второй группой """

            def open_the_desired_tab(browser):

                """ Открываем нужную вкладку """

                desired_tab = browser.find_element(
                    By.XPATH,
                    '//div[contains(text(), "Что посетить")]/..'
                )
                self.click_on_button(desired_tab)


            def scroll_down(browser):

                """ Пролистываем вниз """

                def click_show_more(browser):

                    """ Нажимаем показать больше """

                    def check_to_go_out_or_not(button):

                        """ Проверяем выходить или нет """

                        try:

                            self.click_on_button(button)
                            return 'go out'

                        except MoveTargetOutOfBoundsException as error:

                            print(f'{error}\nДвигаем дальше')
                            return 'dont go out'


                    # ВЫШЕ ОПРЕДЕЛЕНИЕ ФУНКЦИЙ

                    while True:

                        show_more_button = browser.find_element(
                            By.XPATH,
                            '//div[@class="business-tab-wrapper _materialized"]//div[contains(text(), "Показать ещё")]'
                        )
                        self.scroll_the_sidebar()

                        well_what = check_to_go_out_or_not(show_more_button)
                        if well_what == 'go out': break



                # ВЫШЕ ОПРЕДЕЛЕНИЕ ФУНКЦИЙ

                while True:

                    well_what = self.scroll_further(browser)
                    if well_what == 'end': break

                    click_show_more(browser)
                    time.sleep(2)


            # ВЫШЕ ОПРЕДЕЛЕНИЕ ФУНКЦИИ

            open_the_desired_tab(browser)
            scroll_down(browser)


        # ВЫШЕ ОПРЕДЕЛЕНИЕ ФУНКЦИЙ

        match what_here:

            case 'first element':

                work_with_the_first_group(browser)

            case 'second element':

                work_with_the_second_group(browser)

            case _:

                print(f'Непонятно с какими элементами работать\nwhat_here - {what_here}')


    def get_the_address_and_type_of_activity(self, address):

        """ Получаем адрес и вид деятельности """

        # Москва, район: Коньково; параметры: Стоматология

        #address, type_of_activity = address.split(' параметры:')

        print(f'address - {address}')

        what_here = re.findall('район|параметры', address)

        if len(what_here) == 2:

            address, type_of_activity = address.split(';')

            address = ''.join(address.split(' район:'))

            type_of_activity = type_of_activity.split(' параметры: ')[1]
            type_of_activity = type_of_activity.strip().title()

            return address + ' ' + type_of_activity, type_of_activity

        if what_here[0] == 'район':

            address = ''.join(address.split(' район:'))
            type_of_activity = 'Вид деятельности не указан'

            return address, type_of_activity

        if what_here[0] == 'параметры':

            address = ''.join(address.split(' параметры:'))
            type_of_activity = 'Вид деятельности не был указан'

            return address, type_of_activity



    def get_the_company_name(self, browser):

        """ Получаем название компании """

        company_name = browser.find_element(
            By.XPATH,
            '//h1[@itemprop="name"]'
        ).text

        return company_name


    def get_the_full_address_of_the_place(self, browser):

        """ Получаем адрес места """

        full_address = browser.find_element(
            By.XPATH,
            '//a[@class="orgpage-header-view__address"]'
        ).text

        return full_address


    def get_all_numbers(self, browser):

        """ Получаем все номера """

        def click_show_phone(browser):

            """ Нажимаем 'Показать телефон' """

            while True:

                try:

                    button = browser.find_element(
                        By.XPATH,
                        '//*[contains(text(), "Контакты")]/../../..//div[contains(text(), "Показать телефон")]'
                    )

                except NoSuchElementException as error:

                    self.scroll_the_page_js(browser, h=500)
                    return 'Телефон не указан'

                try:

                    self.click_on_button(button)
                    break

                except MoveTargetOutOfBoundsException as error:

                    print(f'Не попал\n{error}')
                    scroll_the_sidebar(height=-20)


        def click_show_all_phones(browser):

            """ Нажимаем 'Показать все телефоны' """

            while True:

                button = browser.find_element(
                    By.XPATH,
                    '//*[contains(text(), "Контакты")]/../../following-sibling::div[@class="card-phones-view _wide"]'
                )

                try:

                    self.click_on_button(button)
                    break

                except MoveTargetOutOfBoundsException as error:

                    print(f'Не попал\n{error}')
                    scroll_the_sidebar(height=-20)


        def get_numbers(browser):

            """ Получаем номера """

            result = []
            numbers_selenium = browser.find_elements(
                By.XPATH,
                '//*[contains(text(), "Контакты")]/../../following-sibling::div[@class="card-phones-view _wide"]//div[@class="card-phones-view__phone-number"]'
            )

            for element in numbers_selenium:

                number = element.text
                result.append(number)

            return '\n'.join(result)


        # ВЫШЕ ОПРЕДЕЛЕНИЕ ФУНКЦИЙ

        number = click_show_phone(browser)
        if number == 'Телефон не указан': return 'Телефон не указан'

        click_show_all_phones(browser)
        numbers = get_numbers(browser)

        return numbers


    def get_links_to_website(self, browser):

        """ Получаем ссылки сайтов """

        def get_a_list_of_links(browser):

            """ Получаем список ссылок """

            while True:

                try:

                    button = browser.find_element(
                        By.XPATH,
                        '//*[contains(text(), "Контакты")]/../../following-sibling::div//div[@class="card-feature-view__value"]'
                    )
                    self.click_on_button(button)
                    self.scroll_the_sidebar(height=-50)
                    break

                except MoveTargetOutOfBoundsException as error:

                    self.scroll_the_sidebar(height=-20)

            list_of_links_selenium = browser.find_elements(
                By.XPATH,
                '//*[contains(text(), "Контакты")]/../../following-sibling::div/following-sibling::div//a[@class="business-urls-view__link"]'
            )

            result = [element.get_attribute('href') for element in list_of_links_selenium]

            return '\n'.join(result)


        # ВЫШЕ ОПРЕДЕЛЕНИЕ ФУНКЦИЙ

        well_what = self.waiting_for_one_thing(
            browser,
            '//a[@class="business-urls-view__link"]',
            '//*[contains(text(), "Контакты")]/../../following-sibling::div//div[@class="card-feature-view__value"]',
            disable=True
        )

        match well_what:

            case 'first element':

                link_to_the_website = browser.find_element(
                    By.XPATH,
                    '//a[@class="business-urls-view__link"]'
                ).get_attribute('href')

                return link_to_the_website

            case 'second element':

                list_of_links = get_a_list_of_links(browser)
                return list_of_links

            case 'elements are missing':

                return 'Сайт не был указан в Яндекс Картах'


    def get_email_yandex_map(self, browser):

        """ Получаем почту с яндекса """

        return 'email yandex map'


    def get_the_mail_list_from_the_website(self, browser, list_of_links):

        """ Получить список почт с сайта """

        sm = search_mail.SearchMail(browser, list_of_links)

        list_of_emails_from_the_site = sm.start_mail_search()
        if list_of_emails_from_the_site == 'Сайт не был указан в Яндекс Картах': return 'Сайт не был указан в Яндекс Картах'
        if list_of_emails_from_the_site == 'blocking': return 'Заблокировали на сайте'

        list_of_emails_from_the_site = '\n'.join(list(list_of_emails_from_the_site))

        print(f'Email для записи - {list_of_emails_from_the_site}')

        return list_of_emails_from_the_site
